import 'dart:math' as Math;
import 'package:flutter/material.dart';

class CustomMultiChildLayoutPage extends StatefulWidget {
  @override
  _CustomMultiChildLayoutPageState createState() =>
      _CustomMultiChildLayoutPageState();
}

class _CustomMultiChildLayoutPageState
    extends State<CustomMultiChildLayoutPage> {
  List<Widget> products = [];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    for (int i = 0; i < 5; i++) {
      products.add(LayoutId(
        id: 'BUTTON$i',
        child: Text('$i'),
      ));
    }
  }

  @override
  Widget build(BuildContext context) {
    return CustomMultiChildLayout(
      delegate: _CircularLayoutDelegate(
        itemCount: 5,
        radius: 30.0,
      ),
      children: products,
    );
  }
}

class _CircularLayoutDelegate extends MultiChildLayoutDelegate {
  static const String actionButton = 'BUTTON';
  Offset center;
  final int itemCount;
  final double radius;

  _CircularLayoutDelegate({
    @required this.itemCount,
    @required this.radius,
  });
  static const double _radiansPerDegree = Math.pi / 180;
  final double _startAngle = -90.0 * _radiansPerDegree;
  double _itemSpacing = 360.0 / 5.0;
  double _calculateItemAngle(int index) {
    return _startAngle + index * _itemSpacing * _radiansPerDegree;
  }

  @override
  void performLayout(Size size) {
    center = Offset(size.width / 2, size.height / 2);
    for (int i = 0; i < itemCount; i++) {
      final String actionButtonId = '$actionButton$i';

      if (hasChild(actionButtonId)) {
        final Size buttonSize =
            layoutChild(actionButtonId, BoxConstraints.loose(size));
        final double itemAngle = _calculateItemAngle(i);

        positionChild(
          actionButtonId,
          Offset(
            (center.dx - buttonSize.width / 2) + (radius) * Math.cos(itemAngle),
            (center.dy - buttonSize.height / 2) +
                (radius) * Math.sin(itemAngle),
          ),
        );
      }
    }
  }

  @override
  bool shouldRelayout(_CircularLayoutDelegate oldDelegate) =>
      itemCount != oldDelegate.itemCount || radius != oldDelegate.radius;
}
